﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using ArgusLib.Xml;
using ArgusLib.Drawing;

namespace ArgusLib.Fractals.OrbitFractals
{
	public abstract class Renderer : IRenderer
	{
		IRenderParameter IRenderer.Parameter { get { return this.Parameter_get(); } set { this.Parameter_set(value); } }
		protected abstract IRenderParameter Parameter_get();
		protected abstract void Parameter_set(IRenderParameter value);

		public abstract IDataSetProvider GetCompatibleDataSetProvider();

		public abstract bool SupportsDataSet(IDataSet dataSet);

		public abstract bool SupportsDataSet(Type dataSetType);

		public Bitmap Render(IDataSet dataSet)
		{
			Bitmap image = new Bitmap(dataSet.DimensionX, dataSet.DimensionY);
			((IRenderer)this).Render(image, dataSet);
			return image;
		}

		public void Render(Bitmap image, IDataSet dataSet)
		{
			using (ExtendedBitmap bitmap = ExtendedBitmap.FromBitmap(image))
			{
				bitmap.BlendMode = BlendMode.Alpha;
				((IRenderer)this).Render(bitmap, dataSet);
			}
		}

		public void Render(ExtendedBitmap image, IDataSet dataSet)
		{
			if (this.SupportsDataSet(dataSet) == false)
				throw new ArgumentException("Not supported.", "dataSet");
			if (dataSet == null)
				throw new ArgumentNullException("dataSet");
			if (image.Width < dataSet.DimensionX || image.Height < dataSet.DimensionY)
				throw new ArgumentException("Image width or height is too small.", "image");

			bool unlock = image.Lock();
			this.RenderCore(image, dataSet);
			if (unlock == true)
				image.Unlock();
		}

		protected abstract void RenderCore(ExtendedBitmap image, IDataSet dataSet);

		void ISerializable.Serialize(Serializer serializer)
		{
			this.Serialize(serializer);
		}
		protected abstract void Serialize(Serializer serializer);

		void ISerializable.Deserialize(Deserializer deserializer)
		{
			this.Deserialize(deserializer);
		}
		protected abstract void Deserialize(Deserializer deserializer);
	}

	public abstract class Renderer<TDataSet, TParameter> : Renderer
		where TDataSet : IDataSet
		where TParameter : IRenderParameter
	{
		public Renderer(TParameter parameter)
			: base()
		{
			this.Parameter = parameter;
		}

		TParameter parameter;
		public TParameter Parameter
		{
			get { return this.parameter; }
			set
			{
				if (value == null)
					throw new ArgumentNullException();
				this.parameter = value;
			}
		}

		protected override IRenderParameter Parameter_get()
		{
			return this.Parameter;
		}

		protected override void Parameter_set(IRenderParameter value)
		{
			this.Parameter = (TParameter)value;
		}

		public override bool SupportsDataSet(IDataSet dataSet)
		{
			return (dataSet is TDataSet);
		}

		public override bool SupportsDataSet(Type dataSetType)
		{
			return dataSetType.Is(typeof(TDataSet));
		}

		protected override void Serialize(Serializer serializer)
		{
			serializer.Serialize("Parameter", this.Parameter);
		}

		protected override void Deserialize(Deserializer deserializer)
		{
			this.Parameter = (TParameter)deserializer.Deserialize();
		}
	}
}
